根據 CWE-22 的定義:
The software uses external input to construct a pathname that is intended to identify a file or directory that is located underneath a restricted parent directory, but the software does not properly neutralize special elements within the pathname that can cause the pathname to resolve to a location that is outside of the restricted directory.
Path traveral 主要出現在需要透過 路徑 來存取檔案的功能中,最明顯的 payload 就是出現大量的 ../
,透過相對路徑去讀取檔案 (CWE-23),但偶爾業會有直接透過絕對路徑存取的例子 (CWE-36)
但不只是 web 服務,其他檔案分享服務,像是:FTP、SMB 等 service 也經常被發現存在 path traversal 的問題,今天特別放在 web 的分類是因為 path traversal 可以說是被早期 web server 的機制給發揚光大 (?) 了
Web 是基於 HyperText Transfer Protocol (HTTP) 所發展的服務,在最早還沒有動態網頁的時代,網頁要呈現的內容是會先寫在一個靜態的 .html
檔,由 web server 接收到 HTTP request 之後,parse uri 之後得知要存取哪一個頁面,就把該頁面的 .html
的內容讀取到 web server 內,最後包裝成 HTTP response 回傳給使用者
這種 file based 的網頁開發模式在處理靜態網頁一般來說不會出現 path traversal 的問題,原因有兩點:
靜態網頁的功能滿足不了逐漸成長的 Internet,因此後來出現了根據用戶狀態來呈現不同內容的動態網頁,但早期的動態網頁,依然是基於 file based 的機制來設計,因此經常會出現這樣的設計:
http://example.com/show.php?page=people
、http://example.com/show.php?page=product
的 urlpeople.html
, product.html
的靜態頁面page
就可以去存取不同的網頁內容但如果 show.php 沒有去檢查檢查 resource 的路徑, 直接透過 file_get_content()
之類的功能讀取檔案內容並呈現給使用者,就會發生 path traversal 的問題了
雖然現今的 web 開發主流已經逐漸變成 route based 的 design pattern,已經比較少直接將 uri 對應實體的檔案路徑,但只要是有需要自行處理存取檔案的功能都要小心是不是會發生 path traversal 的問題
由於單純 Path Traversal 實在太簡單了 = =,想不到什麼比較經典的 web 題目,因此就拿 LFI 的題目充數......
這題類似上面舉的例子,典型的 php + path traversal (LFI) 的問題,網站上可以透過 index.php?page=$action
開啟另外兩個頁面:view
和 upload
由於 php 的網頁會被 php-fpm 之類的程序執行之後才得到結果,因此沒辦法直接取得 php 的原始碼,但在大多數的情況,基於 php 的 LFI 都可以透過 php 特有的 wrapper 來讀取任意檔案,因此我們也可以用以下的 payload 取得 index.php 和其他兩個頁面的 source
http://website/index.php?page=php://filter/convert.base64-encode/resource=index
include(null_filter($var).".php");
,因為後面會補上 .php
,因此我們的 payload 才不用寫完整的檔案名稱取得 source 之後也會得知在 LFI 之前 index.php 有對 page 的內容進行過濾,因此沒辦法直接透過 ../
跳脫出網頁目錄,也沒辦法根據 http 或 ftp 等外部協定進行 RFI (Remote File Includion)
在 index.php 能做的事情受限了,但別忘了我們還可以透過 upload.php 上傳檔案,從 source 我們可以知道上傳只限制了檔案大小,不限制檔案類型,但最後都會被 rename 成 $random_str.jpg
,由於 LFI 的部分會補上 .php
的後綴,這表示我們沒辦法直接把上傳檔案的內容用 LFI 執行,否則就可以直接達成 RCE 了
但 php wrapper 能做的事情遠不只讀 source code,還可以透過 phar://
或 zip://
之類的協定對檔案進行解壓縮之後,執行裡面的 php 指令
因此我們可以把我們想執行的 php code 包裝成 phar 透過 upload.php 上傳,最後透過以下 payload 來達成 RCE:
http://website/index.php?page=phar:///var/www/owlur/owlur-upload-zzzzzz/bznAQAd.jpg/z&code=echo file_get_contents('/OWLUR-FLAG.txt');